import * as THREE from 'three'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'

interface Ipostion{
  x: number
  y: number
  z: number
}

class SceneFactory{
  container: HTMLElement
  scene: THREE.Scene | null
  camera: THREE.PerspectiveCamera | null
  renderer: THREE.WebGLRenderer | null
  controls: OrbitControls | null
  containerWidth: number | null
  containerHeight: number | null
  constructor(selector: string){
    this.container = document.querySelector(selector) as HTMLElement// 获取容器
    this.containerWidth = null
    this.containerHeight = null
    this.scene = null
    this.camera = null
    this.renderer = null
    this.controls = null
    this.getDomSize()
    this.init()
    this.animate() //循环函数
  }
  init(){
    this.initSence() // 初始化场景
    // this.initAxesHelper() // 初始化坐标轴
    this.initCamera() // 初始化相机
    this.initLight() // 初始化灯光
    this.initRender() // 初始化渲染器
    this.initControls() // 初始轨道控制器
    window.addEventListener('resize', this.onWindowResize.bind(this))
  }

  getDomSize(){
    this.containerWidth = window.innerWidth
    this.containerHeight = window.innerHeight
  }


  initAxesHelper(){
    const axesHelper = new THREE.AxesHelper(10);
    this.scene!.add(axesHelper)
  }

  initSence(){
    this.scene = new THREE.Scene()
    this.scene.background = new THREE.Color(0x000000)
  }

  initCamera(){
    this.camera = new THREE.PerspectiveCamera(75, this.containerWidth! / this.containerHeight!, 0.1, 100)
    this.camera.position.set(3,2,2)
  }

  initRender(){
    this.renderer = new THREE.WebGLRenderer({antialias: true}) // 渲染器设置抗锯齿
    this.renderer.setPixelRatio(window.devicePixelRatio) // 设置像素比
    this.renderer.setSize(this.containerWidth!, this.containerHeight!) // 设置渲染器尺寸
    this.container.appendChild(this.renderer.domElement) // 将渲染器添加到容器中
  }
  render(){
    this.controls!.update()
    this.renderer!.render(this.scene!, this.camera!)
  }
  animate(){
    this.renderer!.setAnimationLoop(this.render.bind(this))
  }

  initControls(){
    this.controls = new OrbitControls(this.camera!, this.renderer!.domElement)
    this.controls.autoRotate = true
    this.controls.autoRotateSpeed = 1
    this.controls.enablePan = false
    this.controls.minDistance =1
    this.controls.maxDistance = 5
    this.controls.addEventListener('change',()=>{
      const cameraPosition = this.camera!.position
      if( cameraPosition.y < 0.5 || cameraPosition.y >4.5){
        this.controls?.reset()
      }else{
        this.controls?.saveState()
      }
      
      
    })
  }

  distanceBetween(positionStart:Ipostion, positionEnd:Ipostion):number{
    const post1 = new THREE.Vector3(positionStart.x, positionStart.y, positionStart.y)
    const post2 = new THREE.Vector3(positionEnd.x, positionEnd.y, positionEnd.z)
    return post1.distanceTo(post2) 
  }

  onWindowResize(){
    if(!this.camera) return
    this.getDomSize()
    this.camera.aspect = this.containerWidth! / this.containerHeight! // 更新相机的宽高比
    this.camera.updateProjectionMatrix() // 更新相机
    this.renderer!.setSize(this.containerWidth!, this.containerHeight!)
  }

  initLight(){
    const hesLight = new THREE.AmbientLight(0xffffff, 1) // 环境光
    this.scene!.add(hesLight)

    const dirLight = new THREE.DirectionalLight(0xffffff,1)  // 
    dirLight.intensity = 3
    dirLight.position.set(2, 2, 2)
    this.scene!.add(dirLight)

    // 聚光灯
    const sportLight = new THREE.SpotLight(0xffffff,1)
    sportLight.visible = true
    sportLight.intensity = 5  // 聚光灯强度
    sportLight.angle = Math.PI / 2 // 聚光灯的锥体角度
    sportLight.penumbra = 0.1 // 聚光灯的尾部衰减
    sportLight.decay = 1 // 纵向：沿着光照距离的衰减量
    sportLight.distance = 100 // 聚光灯的照射距离
    sportLight.shadow.radius = 10 // 聚光灯阴影的模糊半径
    sportLight.shadow.mapSize.set(4096,4096)  // 聚光灯阴影的分辨率
    sportLight.position.set(-2,2,0) // 聚光灯的位置
    sportLight.target.position.set(0,0,0) // 聚光灯照射的目标位置
    sportLight.castShadow = true // 是否开启阴影
    this.scene!.add(sportLight)
  }

  getScene(){
    return this.scene
  }
}

export default SceneFactory